#include <windows.h>

typedef struct
{
	HWND hWnd;
	COLORREF color;
} ThreadData;

const char g_szClassName[] = "myWindowClass";

HANDLE hMutex;
ThreadData DataArray[3];
DWORD dwThreadIdArray[3];
HANDLE hThreadArray[3];
short IS_RUNNING = 1;

DWORD WINAPI ThreadFunction(LPVOID lpParam)
{
	ThreadData *data;
	DWORD dwWaitResult;
	HDC dc;
	RECT rect;
	HGDIOBJ prev_obj;
	HBRUSH hBrush;
	int width, height;


	data = (ThreadData *) lpParam;

	while (1)
	{
		dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
		if (IS_RUNNING)
		{
			GetClientRect(data->hWnd, &rect);
			width = rect.right - rect.left;
			height = rect.bottom - rect.top;

			dc = GetDC(data->hWnd);

			hBrush = CreateSolidBrush(data->color);
			prev_obj = SelectObject(dc, hBrush);

			Rectangle(dc, 0, 0, width, height);

			SelectObject(dc, prev_obj);
			DeleteObject(hBrush);

			ReleaseDC(data->hWnd, dc);

			Sleep(1000);
		}
		ReleaseMutex(hMutex);
		Sleep(500);
	}

	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
		case WM_KEYDOWN:
			/* if spacebar is pressed */
			if (wParam == VK_SPACE)
				IS_RUNNING = !IS_RUNNING;
			break;
		case WM_PAINT:
			break;
		case WM_CLOSE:
			DestroyWindow(hWnd);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
		LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;
	HWND hWnd;
	MSG Msg;
	int i;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = g_szClassName;
	wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

	if(!RegisterClassEx(&wc))
	{
		MessageBox(NULL, "Window Registration Failed!", "Error!",
				MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	hWnd = CreateWindowEx(
			WS_EX_CLIENTEDGE,
			g_szClassName,
			"Mutex based sync",
			WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT, 480, 270,
			NULL, NULL, hInstance, NULL);

	if(hWnd == NULL)
	{
		MessageBox(NULL, "Window Creation Failed!", "Error!",
				MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	hMutex = CreateMutex( 
			NULL,              // default security attributes
			FALSE,             // initially not owned
			NULL);             // unnamed mutex
	if (hMutex == NULL)
	{
		MessageBox(NULL, "Mutex Creation Failed!", "Error!",
				MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}

	DataArray[0].color = RGB(255, 255, 0);
	DataArray[1].color = RGB(0, 0, 255);
	DataArray[2].color = RGB(0, 0, 0);
	for (i = 0; i < 3; i++)
	{
		DataArray[i].hWnd = hWnd;
		hThreadArray[i] = CreateThread( 
				NULL,                   // default security attributes
				0,                      // use default stack size  
				ThreadFunction,			// thread function name
				&DataArray[i],			// argument to thread function 
				0,                      // use default creation flags 
				&dwThreadIdArray[i]);   // returns the thread identifier 
		if (hThreadArray[i] == NULL)
		{
			MessageBox(NULL, "Thread Creation Failed!", "Error!",
					MB_ICONEXCLAMATION | MB_OK);
			return 0;
		}
	}

	while(GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	return Msg.wParam;
}
